home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3.2 / Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO / packet / n17jsrc / nr4.c < prev    next >
C/C++ Source or Header  |  1991-08-08  |  21KB  |  747 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "ax25.h"
  12. #include "lapb.h"
  13. #include "netrom.h"
  14. #include "nr4.h"
  15. #include <ctype.h>
  16.  
  17. #undef NR4DEBUG
  18.  
  19. /* Globals: */
  20.  
  21. /* The circuit table */
  22.  
  23. struct nr4circp Nr4circuits[NR4MAXCIRC];
  24.  
  25. /* Various limits */
  26.  
  27. unsigned short Nr4window = 4;        /* Max window to negotiate */
  28. unsigned short Nr4retries = 10;    /* Max retries */
  29. unsigned short Nr4qlimit = 2048;    /* Max bytes on receive queue */
  30.  
  31. /* Timers */
  32.  
  33. int32 Nr4irtt = 15000;            /* Initial round trip time */
  34. int32 Nr4acktime = 3000;        /* ACK delay timer */
  35. int32 Nr4choketime = 180000;        /* CHOKEd state timeout */
  36.  
  37. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  38. static void nr4choke __ARGS((struct nr4cb *));
  39. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  40. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  41.  
  42. /* This function is called when a net/rom layer four frame */
  43. /* is discovered inside a datagram addressed to us */
  44.  
  45. void
  46. nr4input(hdr,bp)
  47. struct nr4hdr *hdr;
  48. struct mbuf *bp;
  49. {
  50.     struct nr4hdr rhdr;
  51.     struct nr4cb *cb, *cb2;
  52.     int op;
  53.     unsigned window;
  54.     int acceptc;        /* indicates that connection should be accepted */
  55.     int newconn;        /* indicates that this is a new incoming */
  56.                         /* connection.  You'll see. */
  57.     int gotchoke;        /* The choke flag was set in this packet */
  58.     int i;
  59.     long t;
  60.     
  61.     op = hdr->opcode & NR4OPCODE;    /* Mask off flags */
  62.     
  63.     if(op == NR4OPCONRQ){            /* process connect request first */
  64.         acceptc = 1;
  65.         newconn = 0;
  66.  
  67.         /* These fields are sent regardless of success */
  68.         rhdr.yourindex = hdr->u.conreq.myindex;
  69.         rhdr.yourid = hdr->u.conreq.myid;
  70.  
  71.         /* Check to see if we have already received a connect */
  72.         /* request for this circuit. */
  73.         if((cb = match_n4circ(hdr->u.conreq.myindex,
  74.          hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
  75.          == NULLNR4CB){    /* No existing circuit if NULL */
  76.  
  77.             /* Try to get a new circuit */
  78.             if((cb = new_n4circ()) == NULLNR4CB)
  79.                 acceptc = 0;
  80.             /* See if we have any listening sockets */
  81.             for(i = 0; i < NR4MAXCIRC; i++){
  82.                 if((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  83.                 continue;/* not an open circuit */
  84.                 if(cb2->state == NR4STLISTEN)
  85.                     /* A listener was found */
  86.                     break;
  87.             }
  88.             if(i == NR4MAXCIRC){ /* We are refusing connects */
  89.                 acceptc = 0;
  90.                 free_n4circ(cb);
  91.             }
  92.             if(acceptc){
  93.                 /* Load the listeners settings */
  94.                 cb->clone = cb2->clone;
  95.                 cb->user = cb2->user;
  96.                 cb->t_upcall = cb2->t_upcall;
  97.                 cb->s_upcall = cb2->s_upcall;
  98.                 cb->r_upcall = cb2->r_upcall;
  99.                 ASSIGN(cb->local,cb2->local);
  100.  
  101.                 /* Window is set to min of the offered
  102.                  * and local windows
  103.                  */
  104.                 window = hdr->u.conreq.window > Nr4window ?
  105.                          Nr4window : hdr->u.conreq.window;
  106.  
  107.                 if(init_nr4window(cb, window) == -1){
  108.                     free_n4circ(cb);
  109.                     acceptc = 0;
  110.                 } else {
  111.                     /* Set up control block */
  112.                     cb->yournum = hdr->u.conreq.myindex;
  113.                     cb->yourid = hdr->u.conreq.myid;
  114.                     memcpy(cb->remote.user,
  115.                            hdr->u.conreq.user,AXALEN);
  116.                     memcpy(cb->remote.node,
  117.                            hdr->u.conreq.node,AXALEN);
  118.                     /* Default round trip time */
  119.                     cb->srtt = Nr4irtt;
  120.                     /* set up timers, window pointers */
  121.                     nr4defaults(cb);
  122.                     cb->state = NR4STDISC;
  123.                     newconn = 1;
  124.                 } /* End if window successfully allocated */
  125.             }    /* End if new circuit available */
  126.          } /* End if no existing circuit matching parameters */
  127.  
  128.         /* Now set up response */
  129.         if(!acceptc){
  130.             rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
  131.             rhdr.u.conack.myindex = 0;
  132.             rhdr.u.conack.myid = 0;
  133.             rhdr.u.conack.window = 0;
  134.         } else {
  135.             rhdr.opcode = NR4OPCONAK;
  136.             rhdr.u.conack.myindex = cb->mynum;
  137.             rhdr.u.conack.myid = cb->myid;
  138.             rhdr.u.conack.window = cb->window;
  139.         }
  140.         nr4sframe(hdr->u.conreq.node, &rhdr, NULLBUF);
  141.  
  142.         /* Why, you ask, do we wait until now for the state change
  143.          * upcall?  Well, it's like this:  if the state change triggers
  144.          * something like the mailbox to send its banner, the banner
  145.          * would have gone out *before* the conn ack if we'd done this
  146.          * in the code above.  This is what happens when you don't plan
  147.          * too well.  Learn from my mistakes :-)
  148.          */
  149.         if(newconn)
  150.             nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
  151.             
  152.         free_p(bp);
  153.         return;
  154.     } /* end connect request code */
  155.  
  156.     /* validate circuit number */
  157.     if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB){
  158.         free_p(bp);
  159.         return;
  160.     }
  161.  
  162.     /* Check for choke flag */
  163.     if(hdr->opcode & NR4CHOKE)
  164.         gotchoke = 1;
  165.     else
  166.         gotchoke = 0;
  167.     
  168.     /* Here's where the interesting stuff gets done */
  169.     switch(cb->state){
  170.     case NR4STCPEND:
  171.         switch(op){
  172.         case NR4OPCONAK:
  173.             /* Save the round trip time for later use */
  174.             t = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
  175.             stop_timer(&cb->tcd);
  176.             if(gotchoke){        /* connect rejected */
  177.                 cb->dreason = NR4RREFUSED;
  178.                 nr4state(cb, NR4STDISC);
  179.                 break;
  180.             }
  181.             cb->yournum = hdr->u.conack.myindex;
  182.             cb->yourid = hdr->u.conack.myid;
  183.             window = hdr->u.conack.window > Nr4window ?
  184.                      Nr4window : hdr->u.conack.window;
  185.  
  186.             if(init_nr4window(cb, window) == -1){
  187.                 cb->dreason = NR4RRESET;
  188.                 nr4state(cb, NR4STDISC);
  189.             } else {
  190.                 nr4defaults(cb);    /* set up timers, window pointers */
  191.                 
  192.                 if(cb->cdtries == 1)    /* No retries */
  193.                     /* Use measured rtt */
  194.                     cb->srtt = t;
  195.                 else
  196.                     /* else use default */
  197.                     cb->srtt = Nr4irtt;
  198.                     
  199.                 nr4state(cb, NR4STCON);
  200.                 nr4output(cb);        /* start sending anything on the txq */
  201.             }
  202.             break;
  203.         default:
  204.             /* We can't respond to anything else without
  205.              * Their ID and index
  206.              */
  207.               free_p(bp);
  208.             return;
  209.         }
  210.         break;
  211.     case NR4STCON:
  212.         switch(op){
  213.         case NR4OPDISRQ:
  214.             /* format reply packet */
  215.             rhdr.opcode = NR4OPDISAK;
  216.             rhdr.yourindex = cb->yournum;
  217.             rhdr.yourid = cb->yourid;
  218.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  219.             cb->dreason = NR4RREMOTE;
  220.             nr4state(cb, NR4STDISC);
  221.             break;
  222.           case NR4OPINFO:
  223.             /* Do receive frame processing */
  224.               nr4rframe(cb, hdr->u.info.txseq, bp);
  225.  
  226.             /* Reset the choke flag if no longer choked.  Processing
  227.              * the ACK will kick things off again.
  228.              */
  229.             if(cb->choked && !gotchoke){
  230.                 stop_timer(&cb->tchoke);
  231.                 cb->choked = 0;
  232.             }
  233.                 
  234.             /* We delay processing the receive sequence number until
  235.              * now, because the ACK might pull more off the txq and send
  236.              * it, and we want the implied ACK in those frames to be right
  237.              *
  238.              * Only process NAKs if the choke flag is off.  It appears
  239.              * that NAKs should never be sent with choke on, by the way,
  240.              * but you never know, considering that there is no official
  241.              * standard for this protocol
  242.              */
  243.             if(hdr->opcode & NR4NAK && !gotchoke)
  244.                 nr4gotnak(cb, hdr->u.info.rxseq);
  245.  
  246.             /* We always do ACK processing, too, since the NAK of one
  247.              * packet may be the implied ACK of another.  The gotchoke
  248.              * flag is used to prevent sending any new frames, since
  249.              * we are just going to purge them next anyway if this is
  250.              * the first time we've seen the choke flag.  If we are
  251.              * already choked, this call will return immediately.
  252.              */
  253.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke);
  254.  
  255.             /* If we haven't seen the choke flag before, purge the
  256.              * send window and set the timer and the flag.
  257.              */
  258.             if(!cb->choked && gotchoke)
  259.                 nr4choke(cb);
  260.             break;
  261.           case NR4OPACK:
  262.             if(cb->choked && !gotchoke){
  263.                 /* clear choke if appropriate */
  264.                 stop_timer(&cb->tchoke);
  265.                 cb->choked = 0;
  266.             }    
  267.               if(hdr->opcode & NR4NAK && !gotchoke)
  268.                 nr4gotnak(cb, hdr->u.ack.rxseq);    /* process NAKs */
  269.                 
  270.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke); /* and ACKs */
  271.  
  272.             if(!cb->choked && gotchoke)    /* First choke seen */
  273.                 nr4choke(cb);        /* Set choke status */
  274.  
  275.             break;
  276.         }
  277.         break;
  278.     case NR4STDPEND:
  279.         switch(op){
  280.         case NR4OPDISAK:
  281.               cb->dreason = NR4RNORMAL;
  282.             nr4state(cb, NR4STDISC);
  283.             break;
  284.         case NR4OPINFO:
  285.             /* We can still do receive frame processing until
  286.              * the disconnect acknowledge arrives, but we won't
  287.              * bother to process ACKs, since we've flushed our
  288.              * transmit buffers and queue already.
  289.              */
  290.               nr4rframe(cb, hdr->u.info.txseq, bp);
  291.             break;
  292.         }
  293.     }    /* End switch(state) */
  294. }
  295.  
  296.  
  297. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  298.  * type is info.
  299.  */
  300. void
  301. nr4sframe(dest, hdr, bp)
  302. char *dest;
  303. struct nr4hdr *hdr;
  304. struct mbuf *bp;
  305. {
  306.     struct mbuf *n4b;
  307.  
  308.     if((n4b = htonnr4(hdr)) == NULLBUF){
  309.         free_p(bp);
  310.         return;
  311.     } else {
  312.         append(&n4b, bp);
  313.         nr3output(dest, n4b);
  314.     }
  315. }
  316.  
  317. /* Receive frame processing */
  318. static void
  319. nr4rframe(cb, rxseq, bp)
  320. struct nr4cb *cb;
  321. unsigned rxseq;
  322. struct mbuf *bp;
  323. {
  324.     struct nr4hdr rhdr;
  325.     unsigned window = cb->window;
  326.     unsigned rxbuf = rxseq % window;
  327.     unsigned newdata = 0;        /* whether to upcall */
  328.  
  329. #ifdef NR4DEBUG
  330.     printf("Processing received info\n");
  331. #endif
  332.  
  333.     /* If we're choked, just reset the ACK timer to blast out
  334.      * another CHOKE indication after the ackdelay
  335.      */
  336.     if(cb->qfull){
  337.         start_timer(&cb->tack);
  338.         return;
  339.     }
  340.     
  341.     /* If frame is out of sequence, it is either due to a lost frame
  342.      * or a retransmission of one seen earlier.  We do not want to NAK
  343.      * the latter, as the far end would see this as a requirement to
  344.      * retransmit the expected frame, which is probably already in the
  345.      * pipeline.  This in turn would cause another out-of-sequence
  346.      * condition, another NAK, and the process would repeat indefinitely.
  347.      * Therefore, if the frame is out-of-sequence, but within the last
  348.      * 'n' frames by sequence number ('n' being the window size), just
  349.      * accept it and discard it.  Else, NAK it if we haven't already.
  350.      *    (Modified by Rob Stampfli, kd8wk, 9 Jan 1990)
  351.      */
  352.     if(rxseq != cb->rxpected && !cb->naksent){
  353. #ifdef NR4DEBUG
  354.         printf("Frame out of sequence -- expected %u, got %u.\n",
  355.                cb->rxpected, rxseq);
  356. #endif                
  357.         if(nr4between(cb->rxpected,
  358.            (rxseq + window) & NR4SEQMASK, cb->rxpastwin))
  359.             /* just a repeat of old frame -- queue ack for
  360.              * expected frame
  361.              */
  362.             start_timer(&cb->tack);
  363.         else {            /* really bogus -- a NAKable frame */
  364.             rhdr.opcode = NR4OPACK | NR4NAK;
  365.             rhdr.yourindex = cb->yournum;
  366.             rhdr.yourid = cb->yourid;
  367.             rhdr.u.ack.rxseq = cb->rxpected;
  368.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  369.         
  370.             /* Now make sure we don't send any more of these until
  371.              * we see some good data.  Otherwise full window
  372.              * retransmissions would result in a flurry of NAKs
  373.              */
  374.         
  375.             cb->naksent = 1;
  376.         }
  377.     }
  378.             
  379.     /* If this is a new frame, within the window, buffer it,
  380.      * then see what we can deliver
  381.      */
  382.     if(nr4between(cb->rxpected,rxseq,cb->rxpastwin)
  383.         && !cb->rxbufs[rxbuf].occupied){
  384. #ifdef NR4DEBUG
  385.         printf("Frame within window\n");
  386. #endif
  387.         cb->rxbufs[rxbuf].occupied = 1;
  388.         cb->rxbufs[rxbuf].data = bp;
  389.                 
  390.         for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
  391.              rxbuf = cb->rxpected % window){
  392. #ifdef NR4DEBUG
  393.             printf("Removing frame from buffer %d\n", rxbuf);
  394. #endif
  395.             newdata = 1;
  396.             cb->rxbufs[rxbuf].occupied = 0;
  397.             append(&cb->rxq,cb->rxbufs[rxbuf].data);
  398.             cb->rxbufs[rxbuf].data = NULLBUF;
  399.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
  400.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
  401.         }
  402.         if(newdata){
  403.             cb->naksent = 0;    /* OK to send NAKs again */
  404.             if(cb->r_upcall != NULLVFP)
  405.                 (*cb->r_upcall)(cb,len_p(cb->rxq));
  406.  
  407.             /* Now that our upcall has had a shot at the queue, */
  408.             /* see if it's past the queue length limit.  If so, */
  409.             /* go into choked mode (i.e. flow controlled). */
  410.  
  411.             if(len_p(cb->rxq) > Nr4qlimit){
  412.                 cb->qfull = 1;
  413.                 nr4ackit((void *)cb);    /* Tell `em right away */
  414.             } else
  415.                 start_timer(&cb->tack);
  416.         }
  417.     } else     /* It's out of the window or we've seen it already */
  418.         free_p(bp);
  419. }
  420.  
  421.  
  422. /* Send the transmit buffer whose sequence number is seq */
  423. void
  424. nr4sbuf(cb, seq)
  425. struct nr4cb *cb;
  426. unsigned seq;
  427. {
  428.     struct nr4hdr hdr;
  429.     struct mbuf *bufbp, *bp;
  430.     unsigned bufnum = seq % cb->window;
  431.     struct timer *t;
  432.     
  433.     /* sanity check */
  434.     if(bufnum >= cb->window){
  435. #ifdef NRDEBUG
  436.         printf("sbuf: buffer number %u beyond window\n",bufnum);
  437. #endif
  438.         return;
  439.     }
  440.  
  441.     /* Stop the ACK timer, since our sending of the frame is
  442.      * an implied ACK.
  443.      */
  444.     stop_timer(&cb->tack);
  445.     
  446.     /* Duplicate the mbuf, since we have to keep it around
  447.      * until it is acknowledged
  448.      */
  449.     bufbp = cb->txbufs[bufnum].data;
  450.  
  451.     /* Notice that we use copy_p instead of dup_p.  This is because
  452.      * a frame can still be sitting on the AX.25 send queue when it
  453.      * get acknowledged, and we don't want to deallocate its data
  454.      * before it gets sent!
  455.      */
  456.     if((bp = copy_p(bufbp, len_p(bufbp))) == NULLBUF){
  457.         free_mbuf(bp);
  458.         return;
  459.     }
  460.  
  461.     /* Prepare the header */
  462.     if(cb->qfull)                /* are we choked? */
  463.         hdr.opcode = NR4OPINFO | NR4CHOKE;
  464.     else
  465.         hdr.opcode = NR4OPINFO;
  466.     hdr.yourindex = cb->yournum;
  467.     hdr.yourid = cb->yourid;
  468.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
  469.     hdr.u.info.rxseq = cb->rxpected;
  470.     
  471.     /* Send the frame, then set and start the timer */
  472.     nr4sframe(cb->remote.node, &hdr, bp);
  473.  
  474.     t = &cb->txbufs[bufnum].tretry;
  475.     set_timer(t, (1 << cb->blevel) * (4 * cb->mdev + cb->srtt));
  476.     start_timer(t);
  477. }
  478.  
  479. /* Check to see if any of our frames have been ACKed */
  480.  
  481. static void
  482. nr4ackours(cb, seq, gotchoke)
  483. struct nr4cb *cb;
  484. unsigned seq;
  485. int gotchoke;    /* The choke flag is set in the received frame */
  486. {
  487.     unsigned txbuf;
  488.     struct timer *t;
  489.     
  490.     /* If we are choked, there is nothing in the send window
  491.      * by definition, so we can just return.
  492.      */
  493.     if(cb->choked)
  494.         return;
  495.         
  496.     /* Adjust seq to point to the frame being ACK'd, not the one
  497.      * beyond it, which is how it arrives.
  498.      */
  499.     seq = (seq - 1) & NR4SEQMASK;
  500.  
  501.     /* Free up all the ack'd frames, and adjust the round trip
  502.      * timing stuff
  503.      */
  504.     while (nr4between(cb->ackxpected, seq, cb->nextosend)){
  505. #ifdef NR4DEBUG
  506.         printf("Sequence # %u acknowledged\n", seq);
  507. #endif
  508.         cb->nbuffered--;
  509.         txbuf = cb->ackxpected % cb->window;
  510.         free_mbuf(cb->txbufs[txbuf].data);
  511.         cb->txbufs[txbuf].data = NULLBUF;
  512.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
  513.  
  514.         /* Round trip time estimation, cribbed from TCP */
  515.         if(cb->txbufs[txbuf].retries == 0){
  516.             /* We only sent this one once */
  517.             int32 rtt;
  518.             int32 abserr;
  519.  
  520.             t = &cb->txbufs[txbuf].tretry;
  521.             /* get our rtt in msec */
  522.             rtt = dur_timer(t) - read_timer(t);
  523.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
  524.             cb->srtt = (cb->srtt * 7 + rtt) >> 3;
  525.             cb->mdev = (cb->mdev * 3 + abserr) >> 2;
  526.  
  527.             /* Reset the backoff level */
  528.             cb->blevel = 0;
  529.         }
  530.         stop_timer(&cb->txbufs[txbuf].tretry);
  531.     }    
  532.     /* Now we recalculate tmax, the maximum number of retries for
  533.      * any frame in the window.  tmax is used as a baseline to
  534.      * determine when the window has reached a new high in retries.
  535.      * We don't want to increment blevel for every frame that times
  536.      * out, since that would lead to us backing off too fast when
  537.      * all the frame timers expired at around the same time.
  538.      */
  539.     cb->txmax = 0;
  540.     
  541.     for(seq = cb->ackxpected;
  542.          nr4between(cb->ackxpected, seq, cb->nextosend);
  543.          seq = (seq + 1) & NR4SEQMASK)
  544.         if(cb->txbufs[seq % cb->window].retries > cb->txmax)
  545.             cb->txmax = cb->txbufs[seq % cb->window].retries;
  546.  
  547.     /* This is kind of a hack.  This function is called under
  548.      * three different conditions:  either we are choked, in
  549.      * which case we return immediately, or we are not choked,
  550.      * in which case we proceed normally to keep the send
  551.      * window full, or we have seen the choke flag for the first
  552.      * time.  In the last case, gotchoke is true while cb->choked
  553.      * is false.  We want to process any acknowledgments of existing
  554.      * frames in the send window before we purge it, while at the
  555.      * same time we don't want to take anything else off the txq
  556.      * or send it out.  So, in the third case we listed, we return
  557.      * now since we've processed the ACK.
  558.      */
  559.     
  560.     if(gotchoke)
  561.         return;
  562.         
  563.     nr4output(cb);            /* yank stuff off txq and send it */
  564.  
  565.     /* At this point, either the send window is full, or
  566.      * nr4output() didn't find enough on the txq to fill it.
  567.      * If the window is not full, then the txq must be empty,
  568.      * and we'll make a tx upcall
  569.      */
  570.     if(cb->nbuffered < cb->window && cb->t_upcall != NULLVFP)
  571.         (*cb->t_upcall)(cb, (int16)((cb->window - cb->nbuffered) * NR4MAXINFO));
  572.  
  573. }
  574.  
  575.  
  576. /* If the send window is open and there are frames on the txq,
  577.  * move as many as possible to the transmit buffers and send them.
  578.  * Return the number of frames sent.
  579.  */
  580. int
  581. nr4output(cb)
  582. struct nr4cb *cb;
  583. {
  584.     int numq, i;
  585.     struct mbuf *bp;
  586.     struct nr4txbuf *tp;
  587.  
  588.     /* Are we in the proper state? */
  589.     if(cb->state != NR4STCON || cb->choked)
  590.         return 0;        /* No sending if not connected */
  591.                     /* or if choked */
  592.         
  593.     /* See if the window is open */
  594.     if(cb->nbuffered >= cb->window)
  595.         return 0;
  596.  
  597.     numq = len_q(cb->txq);
  598.     
  599. #ifdef NR4DEBUG
  600.     printf("nr4output: %d packets on txq\n", numq);
  601. #endif
  602.     
  603.     for(i = 0; i < numq; i++){
  604.         bp = dequeue(&cb->txq);
  605. #ifdef NR4DEBUG
  606.         if(len_p(bp) > NR4MAXINFO){    /* should be checked higher up */
  607.             printf("Upper layers queued too big a buffer\n");
  608.             continue;
  609.         }
  610. #endif
  611.         /* Set up and send buffer */
  612.         tp = &cb->txbufs[cb->nextosend % cb->window];
  613.         tp->retries = 0;
  614.         tp->data = bp;
  615.         nr4sbuf(cb, cb->nextosend);
  616.  
  617.         /* Update window and buffered count */
  618.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
  619.         if(++cb->nbuffered >= cb->window)
  620.             break;
  621.     }
  622.     return i;        
  623. }
  624.  
  625. void
  626. nr4state(cb, newstate)
  627. struct nr4cb *cb;
  628. int newstate;
  629. {
  630.     int i;
  631.     int oldstate = cb->state;
  632.     
  633.     cb->state = newstate;
  634.  
  635.     switch(cb->state){
  636.     case NR4STDPEND:
  637.         stop_timer(&cb->tchoke);
  638.  
  639.         /* When we request a disconnect, we lose the contents of
  640.          * our transmit queue and buffers, but we retain our ability
  641.          * to receive any packets in transit until a disconnect
  642.          * acknowledge arrives
  643.          */
  644.         free_q(&cb->txq);
  645.         
  646.         for(i = 0; i < cb->window; i++){
  647.             free_mbuf(cb->txbufs[i].data);
  648.             cb->txbufs[i].data = NULLBUF;
  649.             stop_timer(&cb->txbufs[i].tretry);
  650.         }
  651.         
  652.         /* Tidy up stats: roll the top window pointer back
  653.          * and reset nbuffered to reflect this.  Not really
  654.          * necessary, but leads to a bit more truth telling
  655.          * in the status displays.
  656.          */
  657.         cb->nextosend = cb->ackxpected;
  658.         cb->nbuffered = 0;
  659.         break;
  660.       case NR4STDISC:
  661.         stop_timer(&cb->tchoke);
  662.         stop_timer(&cb->tack);
  663.         stop_timer(&cb->tcd);
  664.  
  665.         /* We don't clear the rxq, since the state change upcall
  666.          * may pull something off of it at the last minute.
  667.          */
  668.         free_q(&cb->txq);
  669.  
  670.         /* The following loop will only be executed if the
  671.          * window was set, since when the control block is
  672.          * calloc'd the window field gets a 0 in it.  This
  673.          * protects us from dereferencing an unallocated
  674.          * window buffer pointer
  675.          */
  676.         for(i = 0; i < cb->window; i++){
  677.             free_mbuf(cb->rxbufs[i].data);
  678.             cb->rxbufs[i].data = NULLBUF;
  679.             free_mbuf(cb->txbufs[i].data);
  680.             cb->txbufs[i].data = NULLBUF;
  681.             stop_timer(&cb->txbufs[i].tretry);
  682.         }
  683.         break;
  684.     }
  685.  
  686.     if(oldstate != newstate && cb->s_upcall != NULLVFP)
  687.         (*cb->s_upcall)(cb, oldstate, newstate);
  688.  
  689.     /* We take responsibility for deleting the circuit
  690.      * descriptor.  Don't do this anywhere else!
  691.      */
  692.     if(newstate == NR4STDISC)
  693.         free_n4circ(cb);
  694. }
  695.  
  696. /* Process NAKs.  seq indicates the next frame expected by the
  697.  * NAK'ing station.
  698.  */
  699.  
  700. static void
  701. nr4gotnak(cb, seq)
  702. struct nr4cb *cb;
  703. unsigned seq;
  704. {
  705.     if(nr4between(cb->ackxpected, seq, cb->nextosend))
  706.         nr4sbuf(cb, seq);
  707. }
  708.  
  709.  
  710. /* This is called when we first get a CHOKE indication from the
  711.  * remote.  It purges the send window and sets the choke timer.
  712.  */
  713.  
  714. static void
  715. nr4choke(cb)
  716. struct nr4cb *cb;
  717. {
  718.     unsigned seq;
  719.     struct mbuf *q, *bp;
  720.     struct nr4txbuf *t;
  721.  
  722.     q = cb->txq;
  723.  
  724.     /* We purge the send window, returning the buffers to the
  725.      * txq in the proper order.
  726.      */
  727.     for(seq = (cb->nextosend - 1) & NR4SEQMASK;
  728.          nr4between(cb->ackxpected, seq, cb->nextosend);
  729.          seq = (seq - 1) & NR4SEQMASK){
  730.  
  731.         t = &cb->txbufs[seq % cb->window];
  732.         stop_timer(&t->tretry);
  733.         bp = t->data;
  734.         t->data = NULLBUF;
  735.         enqueue(&bp, q);    /* prepend this packet to the queue */
  736.         q = bp;
  737.      }
  738.  
  739.     cb->nextosend = cb->ackxpected;    /* close the window */
  740.     cb->nbuffered = 0;        /* nothing in the window */
  741.     cb->txq = q;            /* Replace the txq with the one that has */
  742.                     /* the purged packets prepended */
  743.     cb->choked = 1;        /* Set the choked flag */
  744.  
  745.     start_timer(&cb->tchoke);
  746. }
  747.